//+------------------------------------------------------------------+
//|                        CheckGroup.mqh 复选框组控件接口类          |
//|                版权所有 2000-2025, MetaQuotes Ltd.              |
//|                        官方网址: https://www.mql5.com            |
//+------------------------------------------------------------------+
//| 依赖说明：基于窗口容器类实现，集成多个复选框（CCheckBox），支持滚动 |
//| 核心功能：图表上的复选框组控件，用于批量管理多个选项的选中状态       |
//+------------------------------------------------------------------+
#include "WndClient.h"    // 引入客户端窗口类（提供滚动条等基础容器能力）
#include "CheckBox.h"     // 引入复选框类（单个复选框的实现）
#include <Arrays/ArrayString.h>  // 引入字符串数组（存储选项文本）
#include <Arrays/ArrayLong.h>    // 引入长整数数组（存储选项关联值）
#include <Arrays/ArrayInt.h>     // 引入整数数组（存储选项选中状态）

//+------------------------------------------------------------------+
//| CCheckGroup 类（复选框组控件）                                   |
//| 功能：MQL5 图表中的复选框组，支持多选项管理、滚动显示、状态批量读写 |
//| 继承：public CWndClient（具备窗口容器能力，含滚动条、背景等）       |
//| 核心组成：多个 CCheckBox 子控件 + 数组（存储选项文本/值/状态）      |
//+------------------------------------------------------------------+
class CCheckGroup : public CWndClient
  {
private:
   // 子控件：复选框数组（对应组内的每个选项）
   CCheckBox         m_rows[];              // 复选框数组（仅显示可见范围内的选项）

   // 布局配置参数
   int               m_offset;              // 第一个可见选项在数组中的索引（滚动偏移量）
   int               m_total_view;          // 可见选项数量（由控件高度和单选项高度决定）
   int               m_item_height;         // 单个选项的高度（像素，默认由 CONTROLS_LIST_ITEM_HEIGHT 定义）

   // 数据存储：选项的文本、关联值、选中状态
   CArrayString      m_strings;             // 选项文本数组（所有选项的描述文字）
   CArrayLong        m_values;              // 选项关联值数组（每个选项对应的自定义值）
   CArrayInt         m_states;              // 选项选中状态数组（0=未选中，非0=选中）

   // 当前状态数据
   long              m_value;               // 当前选中选项的关联值总和（按位存储多选项状态）
   int               m_current;             // 当前选中选项在数组中的索引（CONTROLS_INVALID_INDEX 表示无选中）

public:
   //================================================================
   // 1. 构造与析构：初始化/清理复选框组资源
   //================================================================
   /**
    * @brief 构造函数：初始化复选框组默认状态
    * @details 初始化滚动偏移量为0、可见数量为0、单选项高度为默认值，当前选中索引为无效值
    */
                     CCheckGroup(void);

   /**
    * @brief 析构函数：清理复选框组资源
    * @details 依赖父类 CWndClient 析构逻辑，自动释放子控件、数组等资源
    */
                    ~CCheckGroup(void);

   //================================================================
   // 2. 控件创建与销毁：初始化/清理组内布局与子控件
   //================================================================
   /**
    * @brief 在图表指定位置创建复选框组
    * @param chart [in] 目标图表ID（0 表示当前活跃图表，可通过 ChartID() 获取）
    * @param name [in] 控件唯一标识名（图表内不可重复）
    * @param subwin [in] 绑定的子窗口编号（0 = 主图表窗口，≥1 = 指标子窗口）
    * @param x1 [in] 控件左上角X坐标（像素，相对于图表窗口左上角）
    * @param y1 [in] 控件左上角Y坐标（像素）
    * @param x2 [in] 控件右下角X坐标（像素）
    * @param y2 [in] 控件右下角Y坐标（像素）
    * @return bool - 创建结果：true=成功（父类初始化+子控件创建完成），false=失败
    * @note 1. 根据控件高度和单选项高度计算可见选项数量（m_total_view）；
    *       2. 创建可见数量的 CCheckBox 子控件，初始化背景色和边框色
    */
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);

   /**
    * @brief 销毁复选框组（释放子控件与数据）
    * @param reason [in] 销毁原因（默认0，自定义扩展用）
    * @note 清空选项文本、关联值、状态数组，调用父类销毁逻辑释放窗口资源
    */
   virtual void      Destroy(const int reason=0);

   //================================================================
   // 3. 事件处理：响应图表与子控件事件
   //================================================================
   /**
    * @brief 图表事件处理器（统一接收并分发事件）
    * @param id [in] 事件ID（如 ON_CLICK、ON_CHANGE 等）
    * @param lparam [in] 长整数参数（事件相关数据，如子控件索引）
    * @param dparam [in] 双精度参数（事件相关数据）
    * @param sparam [in] 字符串参数（事件相关数据）
    * @return bool - 处理结果：true=事件已处理，false=未处理
    */
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //================================================================
   // 4. 选项管理：添加与配置组内选项
   //================================================================
   /**
    * @brief 向复选框组添加一个选项
    * @param item [in] 选项文本（显示在复选框旁的描述文字）
    * @param value [in] 选项关联值（自定义数值，默认0，用于标识选项状态）
    * @return bool - 添加结果：true=成功（文本、值、状态均存入对应数组），false=失败
    * @note 1. 当选项数量超过可见数量时，自动启用垂直滚动条；
    *       2. 新添加的选项默认未选中（状态存入 m_states 数组）
    */
   virtual bool      AddItem(const string item,const long value=0);

   //================================================================
   // 5. 状态与数据管理：获取/设置选中状态与关联值
   //================================================================
   /**
    * @brief 获取当前所有选中选项的关联值总和（按位存储多选项状态）
    * @return long - 关联值总和（如选项A值为1、选项B值为2，均选中时返回 1|2=3）
    */
   long              Value(void) const;

   /**
    * @brief 设置选中选项的关联值总和（批量更新选项选中状态）
    * @param value [in] 目标关联值总和（通过按位运算匹配对应选项）
    * @return bool - 设置结果：true=成功（更新 m_value 并刷新控件显示），false=失败
    */
   bool              Value(const long value);

   /**
    * @brief 获取指定索引选项的选中状态
    * @param idx [in] 选项索引（从0开始，对应 AddItem 的添加顺序）
    * @return int - 选中状态：0=未选中，非0=选中（返回 m_states 数组中对应值）
    */
   int               Check(const int idx) const;

   /**
    * @brief 设置指定索引选项的选中状态
    * @param idx [in] 选项索引（从0开始）
    * @param value [in] 目标状态（0=未选中，非0=选中）
    * @return bool - 设置结果：true=成功（更新 m_states 数组并刷新控件），false=失败（索引无效）
    */
   bool              Check(const int idx,const int value);

   //================================================================
   // 6. 控件显示：控制复选框组的可见性
   //================================================================
   /**
    * @brief 显示复选框组（包括子控件与滚动条）
    * @return bool - 显示结果：true=成功（调用父类显示逻辑，隐藏超出选项数量的子控件），false=失败
    */
   virtual bool      Show(void);

   //================================================================
   // 7. 序列化：保存/加载复选框组状态到文件
   //================================================================
   /**
    * @brief 将复选框组当前状态（选中值总和）保存到文件
    * @param file_handle [in] 文件句柄（需提前以 FILE_WRITE 模式打开）
    * @return bool - 保存结果：true=成功（写入 m_value 到文件），false=失败（文件无效）
    */
   virtual bool      Save(const int file_handle);

   /**
    * @brief 从文件加载复选框组状态（恢复选中值总和）
    * @param file_handle [in] 文件句柄（需提前以 FILE_READ 模式打开）
    * @return bool - 加载结果：true=成功（从文件读取值并设置到 m_value），false=失败（文件无效）
    */
   virtual bool      Load(const int file_handle);

protected:
   //================================================================
   // 8. 内部子控件管理：创建与配置复选框子控件
   //================================================================
   /**
    * @brief 创建指定索引的复选框子控件（对应组内的一个选项）
    * @param index [in] 子控件索引（对应 m_rows 数组的下标，仅创建可见范围内的控件）
    * @return bool - 创建结果：true=成功（设置子控件位置、尺寸并添加到组内），false=失败
    */
   bool              CreateButton(int index);

   //================================================================
   // 9. 内部事件回调：处理滚动与选项状态变化
   //================================================================
   /**
    * @brief 垂直滚动条显示时的回调（调整子控件宽度，预留滚动条空间）
    * @return bool - 处理结果：true=成功（所有可见子控件宽度缩减，适配滚动条），false=失败
    */
   virtual bool      OnVScrollShow(void);

   /**
    * @brief 垂直滚动条隐藏时的回调（恢复子控件宽度）
    * @return bool - 处理结果：true=成功（所有可见子控件宽度扩展，填满容器），false=失败
    */
   virtual bool      OnVScrollHide(void);

   /**
    * @brief 向上滚动一行时的回调（更新滚动偏移量并刷新显示）
    * @return bool - 处理结果：true=成功（更新 m_offset 并调用 Redraw 刷新选项），false=失败
    */
   virtual bool      OnScrollLineUp(void);

   /**
    * @brief 向下滚动一行时的回调（更新滚动偏移量并刷新显示）
    * @return bool - 处理结果：true=成功（更新 m_offset 并调用 Redraw 刷新选项），false=失败
    */
   virtual bool      OnScrollLineDown(void);

   /**
    * @brief 选项状态变化时的回调（子控件选中/取消选中时触发）
    * @param row_index [in] 状态变化的子控件索引（m_rows 数组的下标）
    * @return bool - 处理结果：true=成功（更新 m_states 数组和 m_value，发送状态变化事件），false=失败
    */
   virtual bool      OnChangeItem(const int row_index);

   //================================================================
   // 10. 内部刷新：更新子控件显示（文本与选中状态）
   //================================================================
   /**
    * @brief 刷新所有可见子控件的显示（同步文本与选中状态）
    * @return bool - 刷新结果：true=成功（遍历可见子控件，设置对应选项的文本和状态），false=失败
    */
   bool              Redraw(void);

   /**
    * @brief 设置指定索引子控件的选中状态
    * @param index [in] 子控件索引（m_rows 数组的下标）
    * @param select [in] 目标状态（true=选中，false=未选中）
    * @return bool - 设置结果：true=成功（调用子控件 Checked 方法），false=失败（索引无效）
    */
   bool              RowState(const int index,const bool select);
  };
//+------------------------------------------------------------------+
//| 事件映射：关联子控件事件到处理函数（用于智能提示识别事件绑定）       |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CCheckGroup)
   // 子控件（m_rows 数组）的 ON_CHANGE 事件 → 调用 OnChangeItem 处理
   ON_INDEXED_EVENT(ON_CHANGE, m_rows, OnChangeItem)
EVENT_MAP_END(CWndClient)
//+------------------------------------------------------------------+